package com.udima.reglocation;

import java.util.Collection;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

import com.udima.reglocation.entities.VehicleType;
import com.udima.reglocation.helpers.JSONHelper;
import com.udima.reglocation.util.AsyncTaskCompleteListener;
import com.udima.reglocation.util.HttpAsyncTask;
import com.udima.reglocation.util.LogHelper;
import com.udima.reglocation.util.PreferencesHandler;

/**
 * 
 * Clase para el registro de la actividad del usuario
 * 
 * @author luis
 *
 */
public class RegisterUserActivity extends Activity implements AsyncTaskCompleteListener {

	private Activity activity = this;

	private static final VehicleType[] vehicleTypes = { VehicleType.STANDARD, VehicleType.SPORT, VehicleType.SUV, VehicleType.MOTO,
			VehicleType.SCOOTER };

	private EditText inputUserUserName;
	private EditText inputUserFirstName;
	private EditText inputUserLastName;
	private EditText inputUserEmail;
	private EditText inputUserEmail2;
	private Spinner inputUserVehicleType;
	private EditText inputUserFetchGpsLapseTime;
	private EditText inputUserPassword;
	private EditText inputUserPassword2;

	private Button btnStoreData;
	private Button btnCancel;


	/**
	 * <p>Método que se ejecuta tras la creación de la actividad</p>
	 *    
	 * En la creación de la clase se instancian los objetos del formulario y se
	 * crean las funciones de escucha para los botones
	 *    
	 * @param savedInstanceState Contiene la información previa de la actividad en caso de que se vuelva a recrear
	 */
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.register_user_activity);

		inputUserUserName = (EditText) findViewById(R.id.inputUserUserName);
		inputUserFirstName = (EditText) findViewById(R.id.inputUserFirstName);
		inputUserLastName = (EditText) findViewById(R.id.inputUserLastName);
		inputUserEmail = (EditText) findViewById(R.id.inputUserEmail);
		inputUserEmail2 = (EditText) findViewById(R.id.inputUserEmail2);
		inputUserFetchGpsLapseTime = (EditText) findViewById(R.id.inputUserFetchGpsLapseTime);
		inputUserVehicleType = (Spinner) findViewById(R.id.inputUserVehicle);
		ArrayAdapter<VehicleType> spinnerAdapter = new ArrayAdapter<VehicleType>(activity, android.R.layout.simple_spinner_item, vehicleTypes);
		inputUserVehicleType.setAdapter(spinnerAdapter);
		inputUserPassword = (EditText) findViewById(R.id.inputUserPassword);
		inputUserPassword2 = (EditText) findViewById(R.id.inputUserPassword2);

		// Listener del boton grabar
		btnStoreData = (Button) findViewById(R.id.btnUserStoreData);
		btnStoreData.setOnClickListener(new View.OnClickListener() {
			public void onClick(View view) {
				storeUserData(view);
			}
		});

		// Listener del boton cancelar
		btnCancel = (Button) findViewById(R.id.btnUserCancelEdit);
		btnCancel.setOnClickListener(new View.OnClickListener() {
			public void onClick(View view) {
				Intent itemintent = new Intent(RegisterUserActivity.this, LoginActivity.class);
				RegisterUserActivity.this.startActivity(itemintent);
			}
		});

	}

	@Override
	/**
	 * Declaracion del interfaz que se invoca tras la consulta http asíncrona
	 * 
	 * @param result Cadena con el resultado de la consulta
	 */
	public void onTaskComplete(String result) {

	}

	/*--------------------------------------------*/

	/**
	 * 
	 * Método para el envio al servidor y posterior almacenaje de los datos de actividad del usuario
	 * 
	 * @param view Estructura de datos con información de la capa
	 * 
	 */
	private void storeUserData(View view) {

		PreferencesHandler ph = new PreferencesHandler(getApplicationContext());
		String appBaseUrl = ph.retrieveAppBaseUrl();

		JSONObject jsonReq = new JSONObject();
		JSONObject jsonUser = new JSONObject();
		try {
			// user data
			jsonUser.put("userName", inputUserUserName.getText().toString());
			jsonUser.put("firstName", inputUserFirstName.getText().toString());
			jsonUser.put("lastName", inputUserLastName.getText().toString());
			jsonUser.put("email", inputUserEmail.getText().toString());
			jsonUser.put("emailRepeated", inputUserEmail2.getText().toString());

			VehicleType vt = (VehicleType) inputUserVehicleType.getSelectedItem();
			jsonUser.put("vehicleType", vt.name());

			jsonUser.put("fetchGpsLapseTime", inputUserFetchGpsLapseTime.getText().toString());

			jsonUser.put("newPassword", inputUserPassword.getText().toString());
			jsonUser.put("newPasswordRepeated", inputUserPassword2.getText().toString());

			jsonReq.put("user", jsonUser);

		} catch (JSONException e) {
			Toast.makeText(getBaseContext(), "Error grave!! Revise el log de la aplicación", Toast.LENGTH_LONG).show();
			LogHelper.logError("Error parsing json result", e);
		}

		// Definición del callback particular para la grabacion de datos
		// de usuario
		final AsyncTaskCompleteListener callback = new AsyncTaskCompleteListener() {

			@Override
			public void onTaskComplete(String result) {
				if (HttpAsyncTask.CONNECTIONERROR.equals(result)) {
					Toast.makeText(getBaseContext(), "Error conectando con el servidor", Toast.LENGTH_LONG).show();
				} else {
					// Primero se transforma el resultado a un objeto Json
					try {
						JSONObject json = new JSONObject(result);

						if (json.getString("responseSuccessful") == "true") {
							Toast.makeText(getBaseContext(), "Registro realizado correctamente", Toast.LENGTH_LONG).show();
							Intent itemintent = new Intent(RegisterUserActivity.this, LoginActivity.class);
							RegisterUserActivity.this.startActivity(itemintent);
						} else {
							Toast.makeText(getBaseContext(), "Hay errores en los datos introducidos. Por favor, revíselos.", Toast.LENGTH_LONG)
									.show();
							processResponseErrors(json.getJSONArray("responseErrors"));
						}
					} catch (JSONException e) {
						Toast.makeText(getBaseContext(), "Error grave!! Revise el log de la aplicación", Toast.LENGTH_LONG).show();
						LogHelper.logError("Error parsing json result", e);
					}
				}
			}
		};

		// Ejecución de la consulta al servicio rest de registro de usuario
		new HttpAsyncTask(activity) {
			@Override
			protected void onPostExecute(String result) {
				super.onPostExecute(result);
				callback.onTaskComplete(result);
			}
		}.execute(appBaseUrl + "/rest/users/register", jsonReq.toString());

	}

	/**
	 * Metodo para procesar errores de la respuesta del servidor
	 * 
	 * @param errors Array Json con la lista de errores recibidos
	 * @throws JSONException
	 */
	private void processResponseErrors(JSONArray errors) throws JSONException {

		hideAllResponseErrorMessages();

		JSONHelper jHelper = new JSONHelper();
		Collection<String> errs = jHelper.JSONArrayToStringCollection(errors);

		for (String err : errs) {

			TextView tv = null;

			if (err.equals("USERNAME_BLANK")) {
				tv = (TextView) findViewById(R.id.errorUserUserName);
				tv.setVisibility(TextView.VISIBLE);
				tv.setText("Introduzca el nombre de usuario");
			} else if (err.equals("USERNAME_EXISTS")) {
				tv = (TextView) findViewById(R.id.errorUserUserName);
				tv.setVisibility(TextView.VISIBLE);
				tv.setText("El nombre de usuario ya existe en el sistema");
			} else if (err.equals("USERNAME_TOOSHORT")) {
				tv = (TextView) findViewById(R.id.errorUserUserName);
				tv.setVisibility(TextView.VISIBLE);
				tv.setText("El nombre de usuario es demasiado corto. Debe tener al menos 8 caracteres");
			} else if (err.equals("FIRSTNAME_BLANK")) {
				tv = (TextView) findViewById(R.id.errorUserFirstName);
				tv.setVisibility(TextView.VISIBLE);
				tv.setText("Introduzca el nombre");
			} else if (err.contains("LASTNAME_BLANK")) {
				tv = (TextView) findViewById(R.id.errorUserLastName);
				tv.setVisibility(TextView.VISIBLE);
				tv.setText("Introduzca los apellidos");
			} else if (err.contains("EMAIL_BLANK")) {
				tv = (TextView) findViewById(R.id.errorUserEmail);
				tv.setVisibility(TextView.VISIBLE);
				tv.setText("Introduzca el email");
			} else if (err.contains("EMAIL_INCORRECT")) {
				tv = (TextView) findViewById(R.id.errorUserEmail);
				tv.setVisibility(TextView.VISIBLE);
				tv.setText("El email tiene un formato incorrecto");
			} else if (err.contains("EMAILS_UNMATCHED")) {
				tv = (TextView) findViewById(R.id.errorUserEmail2);
				tv.setVisibility(TextView.VISIBLE);
				tv.setText("Los emails no coinciden");
			} else if (err.contains("VEHICLETYPE_BLANK")) {
				tv = (TextView) findViewById(R.id.errorUserVehicleType);
				tv.setVisibility(TextView.VISIBLE);
				tv.setText("Introduzca el tipo de vehículo");
			} else if (err.contains("GPSFETCHTIME_BLANK")) {
				tv = (TextView) findViewById(R.id.errorUserGpsFetchTime);
				tv.setVisibility(TextView.VISIBLE);
				tv.setText("Introduzca el intervalo de envío de datos GPS");
			} else if (err.contains("GPSFETCHTIME_INCORRECT")) {
				tv = (TextView) findViewById(R.id.errorUserGpsFetchTime);
				tv.setVisibility(TextView.VISIBLE);
				tv.setText("El intervalo de envío de datos GPS tiene un formato incorrecto");
			} else if (err.contains("GPSFETCHTIME_TOOSMALL")) {
				tv = (TextView) findViewById(R.id.errorUserGpsFetchTime);
				tv.setVisibility(TextView.VISIBLE);
				tv.setText("El intervalo de envío de datos GPS es demasiado alto. Debe encontrarse entre 1000 y 5000 milisegundos");
			} else if (err.contains("GPSFETCHTIME_TOOBIG")) {
				tv = (TextView) findViewById(R.id.errorUserGpsFetchTime);
				tv.setVisibility(TextView.VISIBLE);
				tv.setText("El intervalo de envío de datos GPS es demasiado alto. Debe encontrarse entre 1000 y 5000 milisegundos");
			} else if (err.contains("NEWPASSWORD_BLANK")) {
				tv = (TextView) findViewById(R.id.errorUserPassword);
				tv.setVisibility(TextView.VISIBLE);
				tv.setText("Introduzca la contraseña");
			} else if (err.contains("NEWPASSWORD_PERSONALDATAINCLUDED")) {
				tv = (TextView) findViewById(R.id.errorUserPassword);
				tv.setVisibility(TextView.VISIBLE);
				tv.setText("La contraseña incluye datos personales que la hacen poco segura");
			} else if (err.contains("NEWPASSWORD_TOOSHORT")) {
				tv = (TextView) findViewById(R.id.errorUserPassword);
				tv.setVisibility(TextView.VISIBLE);
				tv.setText("La contraseña es demasiado corta. Debe tener al menos 8 caracteres");
			} else if (err.contains("NEWPASSWORD_CARACTERSNOTALLOWED")) {
				tv = (TextView) findViewById(R.id.errorUserPassword);
				tv.setVisibility(TextView.VISIBLE);
				tv.setText("La contraseña contiene caracteres no permitidos");
			} else if (err.contains("NEWPASSWORD_CARACTERSNOTMIXED")) {
				tv = (TextView) findViewById(R.id.errorUserPassword);
				tv.setVisibility(TextView.VISIBLE);
				tv.setText("La contraseña debe contener al menos tres de los tipos de caracteres siguientes: letras minúsculas, letras mayúsculas, dígitos y caracteres speciales (coma, punto, guión, subrayado, almohadilla)");
			} else if (err.contains("NEWPASSWORDS_UNMATCHED")) {
				tv = (TextView) findViewById(R.id.errorUserPassword2);
				tv.setVisibility(TextView.VISIBLE);
				tv.setText("Las contraseñas no coinciden");
			}
		}

	}

	/**
	 * 
	 * Metodo para ocultar errores visibles
	 * 
	 */
	private void hideAllResponseErrorMessages() {
		((TextView) findViewById(R.id.errorUserUserName)).setVisibility(TextView.GONE);
		((TextView) findViewById(R.id.errorUserFirstName)).setVisibility(TextView.GONE);
		((TextView) findViewById(R.id.errorUserLastName)).setVisibility(TextView.GONE);
		((TextView) findViewById(R.id.errorUserEmail)).setVisibility(TextView.GONE);
		((TextView) findViewById(R.id.errorUserEmail2)).setVisibility(TextView.GONE);
		((TextView) findViewById(R.id.errorUserGpsFetchTime)).setVisibility(TextView.GONE);
		((TextView) findViewById(R.id.errorUserVehicleType)).setVisibility(TextView.GONE);
		((TextView) findViewById(R.id.errorUserPassword)).setVisibility(TextView.GONE);
		((TextView) findViewById(R.id.errorUserPassword2)).setVisibility(TextView.GONE);
	}
}